﻿Imports System.Text
Imports System.ComponentModel
Imports Microsoft.VisualStudio.Language.Intellisense
Imports System.Windows.Input
Imports System.Windows.Controls
Imports Microsoft.VisualStudio.Text
Imports System.Windows
Imports EnvDTE

Namespace Microsoft.VisualStudio.IntellisensePresenter
	Friend Class CompletionSessionPresenter
        Implements IIntellisenseCommandTarget, IPopupIntellisensePresenter
        Private view As CompletionSessionView
        Private mSession As ICompletionSession
        Private serviceProvider As IServiceProvider

        Friend Sub New(ByVal serviceProvider As IServiceProvider, ByVal session As ICompletionSession)
            Me.mSession = session
            AddHandler session.SelectedCompletionSet.SelectionStatusChanged, AddressOf OnSelectedCompletionSetSelectionStatusChanged

            Me.view = New CompletionSessionView(Me)
            Me.view.Select(Me.SelectedCompletion)
            Me.serviceProvider = serviceProvider
        End Sub

        Friend Sub Navigate(ByVal uri As String)
            If Not String.IsNullOrEmpty(uri) Then
                If Not Me.serviceProvider Is Nothing Then
                    Dim vs = TryCast(Me.serviceProvider.GetService(GetType(DTE)), DTE)
                    If Not vs Is Nothing Then
                        vs.ItemOperations.Navigate(uri, vsNavigateOptions.vsNavigateOptionsDefault)
                    End If
                End If
            End If
        End Sub

        Private Sub OnSelectedCompletionSetSelectionStatusChanged(ByVal sender As Object, ByVal e As ValueChangedEventArgs(Of CompletionSelectionStatus))
            If e.NewValue IsNot Nothing AndAlso e.NewValue.Completion IsNot Nothing Then
                Me.view.Select(e.NewValue.Completion)
            End If
        End Sub

        Friend Property SelectedCompletion As Completion
            Get
                Return mSession.SelectedCompletionSet.SelectionStatus.Completion
            End Get
            Set(ByVal value As Completion)
                mSession.SelectedCompletionSet.SelectionStatus = New CompletionSelectionStatus(value, True, True)
            End Set
        End Property

        Friend Sub Commit()
            Me.mSession.Commit()
        End Sub

        ''' <summary>
        ''' 
        ''' </summary>
        Public ReadOnly Property PopupStyles As Microsoft.VisualStudio.Text.Adornments.PopupStyles Implements IPopupIntellisensePresenter.PopupStyles
            Get
                Return Microsoft.VisualStudio.Text.Adornments.PopupStyles.PositionClosest
            End Get
        End Property

        ''' <summary>
        ''' 
        ''' </summary>
        Public ReadOnly Property PresentationSpan As ITrackingSpan Implements IPopupIntellisensePresenter.PresentationSpan
            Get
                Dim span = Me.mSession.SelectedCompletionSet.ApplicableTo.GetSpan(Me.mSession.TextView.TextSnapshot)
                Dim spans = Me.mSession.TextView.BufferGraph.MapUpToBuffer(span, Me.mSession.SelectedCompletionSet.ApplicableTo.TrackingMode, Me.mSession.TextView.TextBuffer)
                If spans.Count <= 0 Then
                    Throw New InvalidOperationException("Completion Session Applicable-To Span is invalid.  It doesn't map to a span in the session's text view.")
                End If
                Dim span2 = spans(0)
                Return Me.mSession.TextView.TextBuffer.CurrentSnapshot.CreateTrackingSpan(span2.Span, SpanTrackingMode.EdgeInclusive)

            End Get
        End Property

        ''' <summary>
        ''' 
        ''' </summary>
        Public ReadOnly Property SpaceReservationManagerName As String Implements IPopupIntellisensePresenter.SpaceReservationManagerName
            Get
                Return "completion"
            End Get
        End Property

        ''' <summary>
        ''' 
        ''' </summary>
        Public ReadOnly Property SurfaceElement As UIElement Implements IPopupIntellisensePresenter.SurfaceElement
            Get
                Return Me.view
            End Get
        End Property

        ''' <summary>
        ''' 
        ''' </summary>
        Public ReadOnly Property Session As IIntellisenseSession Implements IPopupIntellisensePresenter.Session
            Get
                Return Me.mSession
            End Get
        End Property

        ''' <summary>
        ''' 
        ''' </summary>
        Public Property Opacity As Double Implements IPopupIntellisensePresenter.Opacity
            Get
                Return Me.view.Opacity
            End Get
            Set(ByVal value As Double)
                Me.view.Opacity = value
            End Set
        End Property

        ''' <summary>
        ''' 
        ''' </summary>
        ''' <param name="command"></param>
        ''' <returns></returns>
        Public Function ExecuteKeyboardCommand(ByVal command As IntellisenseKeyboardCommand) As Boolean Implements IIntellisenseCommandTarget.ExecuteKeyboardCommand
            Select Case command
                Case IntellisenseKeyboardCommand.Up
                    SelectCompletion(-1)
                    Return True
                Case IntellisenseKeyboardCommand.PageUp
                    SelectCompletion(-10)
                    Return True
                Case IntellisenseKeyboardCommand.Down
                    SelectCompletion(1)
                    Return True
                Case IntellisenseKeyboardCommand.PageDown
                    SelectCompletion(10)
                    Return True
                Case IntellisenseKeyboardCommand.Escape
                    Me.Session.Dismiss()
                    Return True
            End Select

            Return False
        End Function

        Public Event PresentationSpanChanged As EventHandler Implements IPopupIntellisensePresenter.PresentationSpanChanged
        Public Event SurfaceElementChanged As EventHandler Implements IPopupIntellisensePresenter.SurfaceElementChanged

        Private Sub SelectCompletion(ByVal relativeIndex As Integer)
            Dim completionSet = Me.mSession.SelectedCompletionSet

            Dim selectedCompletionIndex = completionSet.Completions.IndexOf(SelectedCompletion) + relativeIndex
            If selectedCompletionIndex < 0 Then
                selectedCompletionIndex = 0
            ElseIf selectedCompletionIndex >= completionSet.Completions.Count Then
                selectedCompletionIndex = completionSet.Completions.Count - 1
            End If

            If selectedCompletionIndex >= 0 AndAlso selectedCompletionIndex < completionSet.Completions.Count Then
                Me.SelectedCompletion = completionSet.Completions(selectedCompletionIndex)
            End If
        End Sub

        Public Event PopupStylesChanged(ByVal sender As Object, ByVal e As Language.Intellisense.ValueChangedEventArgs(Of Text.Adornments.PopupStyles)) Implements Language.Intellisense.IPopupIntellisensePresenter.PopupStylesChanged
    End Class
End Namespace